% Created 2022-04-20 周三 22:59
% Intended LaTeX compiler: xelatex
\documentclass[a4paper]{article}
                 \usepackage{graphicx}
                 \usepackage{xcolor}
                 \usepackage{xeCJK}
                 \usepackage{fixltx2e}
                 \usepackage{longtable}
                 \usepackage{float}        
                 \usepackage{tikz}         
                 \usepackage{wrapfig}      
                 \usepackage{latexsym,amssymb,amsmath}
                 \usepackage{textcomp}
                 \usepackage{bicaption}
                 \usepackage{listings}     
                \usepackage{marvosym}     
                \usepackage{textcomp}     
                \usepackage{latexsym}     
                \usepackage{natbib}
                \usepackage{indentfirst}
		\usepackage{hyperref}
                \usepackage{geometry}
                \usepackage{minted}
                \setCJKmainfont{宋体}
                \setlength{\parindent}{2em}
                \usepackage{color}
                \usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[R]{\footnotesize{《Android 物联网应用程序开发》 广西职业师范学院实验教学指导书}}
\geometry{a4paper,left=2.5cm,right=2.5cm,top=2cm,bottom=2cm}
\setCJKmainfont{仿宋}
\setCJKsansfont{Microsoft YaHei}
\setCJKmonofont{Microsoft YaHei}

            \lstset{
  columns=fixed,       
  breaklines=true, breakautoindent=true,breakindent=4em,
  numbers=left,                                        % 在左侧显示行号
  frame=none,                                          % 不显示背景边框
  backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
  keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
  numberstyle=\footnotesize\color{darkgray},           % 设定行号格式
  commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
  stringstyle=\rmfamily\slshape\color[RGB]{128,0,0},   % 设置字符串格式
  showstringspaces=false,                              % 不显示字符串中的空格
  language=java,                                        % 设置语言
}

\usemintedstyle{emacs}
    \setminted{%
        autogobble,% automatically remove the spaces to the left of the code
        linenos=true,% show line numbers
        fontsize=\small,% smaller font size
        % escapeinside=@@,% insert latex code between @ and @
        frame=lines,% frame styles: none or lines
        % frame=none,
        numbers=none,% show line numbers on: left, right, both or none
        mathescape=true,% insert math code
	breaklines=true,
    }%
    \setmintedinline{%
        fontsize=\smallsize,
    }%
\date{\today}
\title{实验七：Android Service 练习}
\hypersetup{
 pdfauthor={},
 pdftitle={实验七：Android Service 练习},
 pdfkeywords={},
 pdfsubject={},
 pdfcreator={Emacs 27.1 (Org mode 9.3.8)}, 
 pdflang={English}}
\begin{document}

\maketitle
\tableofcontents

\newpage

\section{实验目的}
\label{sec:orge4a3eb0}
\begin{itemize}
\item 掌握Android Service 组件的使用
\end{itemize}
\section{实验设备和器件}
\label{sec:org577f5b6}
\begin{itemize}
\item PC
\item 内存要求 8G 以上
\end{itemize}
\section{实验内容}
\label{sec:orga7fcebb}
\subsection{使用启动模式启动后台Service}
\label{sec:org60515c8}
\subsubsection{实训步骤}
\label{sec:org7caa204}
\begin{itemize}
\item 在AS中新建项目，名称为StartServiceModeDemo
\item 实现本项目的一个Activity和对应的布局文件，即StartServiceModeActivity.java 和 activity\_main.xml
\begin{itemize}
\item activity\_mail.xml
\end{itemize}
\lstset{language=XML,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	      android:layout_width="match_parent"
	      android:layout_height="match_parent"
	      android:orientation="vertical"
	      >
  <TextView  android:id="@+id/label"
	     android:layout_width="fill_parent"
	     android:layout_height="wrap_content"
	     android:text="Hello">
  </TextView>
  <Button android:id="@+id/start"
	  android:layout_width="wrap_content"
	  android:layout_height="wrap_content"
	  android:text="启动Service" >
  </Button>
  <Button android:id="@+id/stop"
	  android:layout_width="wrap_content"
	  android:layout_height="wrap_content"
	  android:text="停止Service" >
  </Button>
</LinearLayout>
\end{lstlisting}
\begin{itemize}
\item StartServiceModeActivity.java :
\end{itemize}
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
   Button startButton = (Button)findViewById(R.id.start);
   Button stopButton = (Button)findViewById(R.id.stop);
   // 定义显示启动所需要的Intent对象，和显示启动Activity类似
   final Intent serviceIntent = new Intent(this, C501Service01.class);

   // 第一个按钮的监听事件，实现启动服务功能
   startButton.setOnClickListener(new Button.OnClickListener(){
	   public void onClick(View view){
		   startService(serviceIntent);
	   }
   });
// 第二个按钮的监听事件，实现停止服务功能
   stopButton.setOnClickListener(new Button.OnClickListener(){
	   public void onClick(View view){
		   // 系统会自动调用服务的生命周期函数停止服务
		   stopService(serviceIntent);
	   }
   });
\end{lstlisting}
\item 新建后台服务类StartServiceModeService.java,继承android.app.Service类，并Override 4个主要方法
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
 @Override
public void onCreate() {
    super.onCreate();
    Toast.makeText(this, "(1) 调用onCreate()方法，初始化服务",
		    Toast.LENGTH_LONG).show();
}

@Override // 每次StartService（）调用都会调用本方法，所以具体功能代码一定在这里实现
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "(2) 调用onStartCommand()方法，实现服务的具体功能",
	    Toast.LENGTH_LONG).show();
    double randomDouble = Math.random();
    String msg = "产生了一个随机数："+ Math.round(randomDouble*100);
    Toast.makeText(this,msg, Toast.LENGTH_LONG).show();
    return super.onStartCommand(intent, flags, startId);
}

@Override // 使用stopService()时，自动调用本方法来停止 Service
public void onDestroy() {
    super.onDestroy();
    Toast.makeText(this, "(3) 调用onDestroy()方法，结束服务",
	    Toast.LENGTH_LONG).show();
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}
\end{lstlisting}
\item 在清单文件中注册该后台服务  
\lstset{language=XML,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
<service
    android:name="StartServiceModeService"
    android:exported="false" />
\end{lstlisting}
\item 调试运行
\end{itemize}
\subsection{使用绑定模式绑定后台Service}
\label{sec:org878b359}
\subsubsection{实训步骤}
\label{sec:org1191540}
\begin{itemize}
\item 新建BindServiceDemoActivity.java,并按照要求创建具体的布局组件
参考布局元素: 一个TextView \& 三个Button
\begin{itemize}
\item TextView用来显示信息
\item 第一个按钮用来绑定服务
\item 第二个按钮用来取消服务的绑定
\item 第三个按钮调用后台服务
\lstset{language=XML,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
<TextView  android:id="@+id/label"
	   android:layout_width="fill_parent"
	   android:layout_height="wrap_content"
	   android:text="hello">
</TextView>
<Button android:id="@+id/bind"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="服务绑定" >
</Button>
<Button android:id="@+id/unbind"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="取消绑定" >
</Button>
<Button android:id="@+id/compute"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="加法运算" >
</Button>
\end{lstlisting}
\end{itemize}
\begin{itemize}
\item BindServiceDemoActivity.java:
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
public class BindServiceDemoActivity extends AppCompatActivity {
    private TextView labelView;
    private MathService mathService;
    private boolean isBound = false;

    private ServiceConnection mConnection = new ServiceConnection() {
	    @Override
	    public void onServiceConnected(ComponentName name, IBinder service) {
		mathService = ((MathService.LocalBinder)service).getService();
	    }

	    @Override
	    public void onServiceDisconnected(ComponentName name) {
		mathService = null;
	    }
	};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);

	labelView = (TextView)findViewById(R.id.label);
	Button bindButton = (Button)findViewById(R.id.bind);
	Button unbindButton = (Button)findViewById(R.id.unbind);
	Button computButton = (Button)findViewById(R.id.compute);

	bindButton.setOnClickListener(new View.OnClickListener(){
		@Override
		public void onClick(View v) {
		    if(!isBound){
			final Intent serviceIntent = new Intent(BindServiceDemoActivity.this,MathService.class);
			bindService(serviceIntent,mConnection, Context.BIND_AUTO_CREATE);
			isBound = true;
		    }
		}
	    });

	unbindButton.setOnClickListener(new View.OnClickListener(){
		@Override
		public void onClick(View v) {
		    if(isBound){
			isBound = false;
			unbindService(mConnection);
			mathService = null;
		    }
		}
	    });

	computButton.setOnClickListener(new View.OnClickListener(){
		@Override
		public void onClick(View v) {
		    if (mathService == null){
			labelView.setText("未绑定服务,请先点击绑定服务按钮后才能实现运算");
			return;
		    }
		    long a = Math.round(Math.random()*100);
		    long b = Math.round(Math.random()*100);
		    long result = mathService.Add(a, b);
		    String msg = String.valueOf(a)+" + "+String.valueOf(b)+
			" = "+String.valueOf(result);
		    labelView.setText(msg);
		}
	    });
    }
}
\end{lstlisting}
\item 新建后台服务类MathService,重构5个重要方法，并设置一个内部类LocalBinder
\begin{itemize}
\item 后台服务类MathService负责复杂逻辑运算
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
    public class MathService extends Service {
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
	C502MathService getService() {
	    return C502MathService.this;
	}
    }

    @Override
    public void onCreate() {
	Toast.makeText(this, "(1) 调用Oncreate()方法",
		Toast.LENGTH_SHORT).show();
	super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
	Toast.makeText(this, "(2) 调用onStartCommand方法",
		Toast.LENGTH_SHORT).show();
	return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
	Toast.makeText(this, "(3) 本地绑定：MathService",
		Toast.LENGTH_SHORT).show();
	return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent){
	Toast.makeText(this, "(4) 取消本地绑定：MathService",
		Toast.LENGTH_SHORT).show();
	return false;
    }
    @Override
    public void onDestroy() {
	Toast.makeText(this, "(5) 调用onDestroy()方法",
		Toast.LENGTH_SHORT).show();
	super.onDestroy();
    }
    public long Add(long a, long b){
	return a+b;
    }
}
\end{lstlisting}
\end{itemize}
\item MathService类中的onBind方法返回一个IBinder的接口实例，该实例能通过getService()函数获得后台
Service的实例
\item 实现后台Service的add方法,该方法为服务端的公共方法
\item 在清单文件中注册后台Service
\end{itemize}
\end{itemize}
\end{document}